﻿#region Legal

// Jimmy Zimmerman
// Team Mongoose
//
// END USER LICENSE AGREEMENT
// IMPORTANT - READ THIS CAREFULLY:  This End User License Agreement is a legal agreement
// between you (either an individual, business entity, currently active identity of an
// individual with Multiple Personality Disorder, octopus overlord, or otherworldly entity),
// and Team Mongoose, for the enclosed, components.
//
// By reading this document and/or installing this product, you agree to be bound by the
// terms of this EULA.
//
// Team Mongoose owns all copyright, trade secret, trademark, trade wars,
// patent, portent, and potential rights to these components.  Team Mongoose
// grants you the right to deploy the enclosed components.
//
// If you agree to the terms of this EULA, a license to use these components is granted to you.
//
// If you should happen to benefit from the enclosed components, then you are legally and
// contractually bound to thank us for it. Send your regards to jimmyzimms@hotmail.com.
//
// OTHER RIGHTS AND LIMITATONS
// You may not reverse-engineer, decompile, decode, disassemble, psycho-analyze, or otherwise
// attempt to find hidden meanings between the lines of this EULA; unless, of course, you should
// happen to find some, and they are funny.
//
// You may not translate this EULA or any part of the components into Ancient Sumerian.
//
// THESE COMPONENTS ARE PROVIDED “AS-IS” WITHOUT WARRANTY OF ANY KIND. ANY USE OF THE COMPONENTS
// CONTAINED IS AT YOUR OWN RISK. TEAM MONGOOSE DISCLAIM ALL WARRANTIES, EITHER
// EXPRESS OR IMPLIED, WITH RESPECT TO THE ACCURRACY AND CORRECTNESS OF THE COMPONENTS CONTAINED
// HEREIN. TEAM MONGOOSE DOES NOT WARRANT THAT THE COMPONENTS ARE FLAWLESS.
//
// REDISTRIBUTION AND USE IN SOURCE AND BINARY FORMS, WITH OR WITHOUT MODIFICATION, ARE PERMITTED
// PROVIDED THAT THE FOLLOWING CONDITIONS ARE MET:
// * REDISTRIBUTIONS OF SOURCE CODE MUST RETAIN THE ABOVE COPYRIGHT NOTICE
// * REDISTRIBUTIONS IN BINARY FORM MUST NOTE THE USE OF THE COMPONENT IN DOCUMENTATION AND/OR
//   OTHER MATERIALS PROVIDED WITH THE DISTRIBUTION.
// * NEITHER THE NAME OF TEAM MONGOOSE MAY BE USED TO ENDORES OR PROMOTE PRODUCTS
//   DERIVED FROM THIS SOFTWARE WITHOUT SPECIFIC PRIOR WRITTEN PERMISSION.
//
// IN NO EVENT SHALL TEAM MONGOOSE BE HELD LIABLE FOR INCIDENTAL, SPECIAL, INDIRECT,
// INCONSEQUENTIAL, UNBELIEVABLE, EXAGGERATED, VERBOSE, OR TYPICAL DAMAGES INCURRED WHILE USING
// THE ENCLOSED COMPONENTS.
//
// OUR STUFF ALWAYS WORKS - SOMETIMES.

#endregion

using System;
using System.ComponentModel;

namespace Mongoose.Games.BfgRoster
{
    /// <summary>
    /// Represents the BFG game turn sequence.
    /// </summary>
    /// <remarks>
    /// The turn sequence consists of the Movement, Shooting, Ordinance, and End phases. This type is responsible 
    /// for coordinating and managing the actions capable of being performed for each phase.
    /// </remarks>
    public class GameTurn : INotifyPropertyChanged
    {
        private Int32 turnNumber;
        private TurnPhases currentPhase = TurnPhases.Order;

        private readonly OrderPhase orderPhase = new OrderPhase();
        private readonly MovementPhase movementPhase = new MovementPhase();
        private readonly ShootingPhase shootingPhase = new ShootingPhase();
        private readonly OrdinancePhase ordinanePhase = new OrdinancePhase();
        private readonly EndPhase endPhase = new EndPhase();

        public enum TurnPhases
        {
            Order,
            Movement,
            Shooting,
            Ordinance,
            End
        }

        /// <summary>
        /// Gets the current turn number for the game.
        /// </summary>
        /// <value>
        /// The current turn number for the game. A value of 0 represents a game that has not started and cannot
        /// execute actions. Once the game has started this value will always be greater than 0. When the value
        /// of this property changes, the <see cref="PropertyChanged"/> event will be raised.
        /// </value>
        public Int32 TurnNumber
        {
            get { return this.turnNumber; }
        }

        /// <summary>
        /// Advances the game to the next phase. If the <see cref="GameTurn"/> is currently in the end phase, the <see cref="TurnNumber"/> will increment.
        /// </summary>
        /// <remarks>
        /// This method will raise the appropriate phase change event: <see cref="MovementPhaseStarted"/>, <see cref="ShootingPhaseStarted"/>,
        /// <see cref="OrdinancePhaseStarted"/>, or <see cref="EndPhaseStarted"/>. If the games is currently in the end phase when this method is called, the
        /// <see cref="TurnNumber"/> will increment and the <see cref="PropertyChanged"/> event will be raised prior to the <see cref="MovementPhaseStarted"/>
        /// event.
        /// </remarks>
        public virtual void NextPhase()
        {
           if (this.turnNumber < 1) throw new InvalidOperationException("The game has not been started");

            Action actionToStart;

           switch (this.currentPhase)
           {
               case (TurnPhases.Order):
                   {
                       actionToStart = this.OnMovementPhaseStarted;
                       break;
                   }
               case (TurnPhases.Movement):
                   {
                       actionToStart = this.OnShootingPhaseStarted;
                       break;
                   }
               case (TurnPhases.Shooting):
                   {
                       actionToStart = this.OnOrdinancePhaseStarted;
                       break;
                   }
               case (TurnPhases.Ordinance):
                   {
                       actionToStart = this.OnEndPhaseStarted;
                       break;
                   }
               case (TurnPhases.End):
                   {
                       actionToStart = this.OnOrderPhaseStarted;
                       break;
                   }
               default:
                   {
                       throw new InvalidOperationException();
                   }
           }

            actionToStart();
        }

        /// <summary>
        /// Begins the game.
        /// </summary>
        public virtual void StartGame()
        {
            if (this.turnNumber > 0) throw new InvalidOperationException("The game is already in progress");

            this.turnNumber = 1;
            this.OnOrderPhaseStarted();
        }

        /// <summary>
        /// Raises the <see cref="OrderPhaseStarted"/> event.
        /// </summary>
        protected virtual void OnOrderPhaseStarted()
        {
            this.currentPhase = TurnPhases.Order;
            this.turnNumber += 1;
            this.OnPropertyChanged("TurnNumber");

            if (this.OrderPhaseStarted == null) return;

            this.OrderPhaseStarted(this, EventArgs.Empty);
        }

        /// <summary>
        /// Event raised when the current <see cref="GameTurn"/> enters the order phase.
        /// </summary>
        /// <remarks>
        /// Any special orders in effect are removed (other than brace for impact) and new orders can be placed.
        /// </remarks>
        public event EventHandler OrderPhaseStarted;

        /// <summary>
        /// Raises the <see cref="MovementPhaseStarted"/> event.
        /// </summary>
        protected virtual void OnMovementPhaseStarted()
        {
            this.currentPhase = TurnPhases.Movement;

            if (this.MovementPhaseStarted == null) return;

            this.MovementPhaseStarted(this, EventArgs.Empty);
        }

        /// <summary>
        /// Event raised when the current <see cref="GameTurn"/> enters the movement phase.
        /// </summary>
        /// <remarks>
        /// This is when the players move their <see cref="Vessel">vessels</see>. In addition, any special orders
        /// in  effect are removed (other than brace for impact).
        /// </remarks>
        public event EventHandler MovementPhaseStarted;

        /// <summary>
        /// Raises the <see cref="ShootingPhaseStarted"/> event.
        /// </summary>
        protected virtual void OnShootingPhaseStarted()
        {
            this.currentPhase = TurnPhases.Shooting;

            if (this.ShootingPhaseStarted == null) return;

            this.ShootingPhaseStarted(this, EventArgs.Empty);
        }

        /// <summary>
        /// Event raised when the current <see cref="GameTurn"/> enters the shooting phase.
        /// </summary>
        /// <remarks>
        /// This is when players may fire at each other's <see cref="Vessel">vessels</see>.
        /// </remarks>
        public event EventHandler ShootingPhaseStarted;

        /// <summary>
        /// Raises the <see cref="OrdinancePhaseStarted"/> event.
        /// </summary>
        protected virtual void OnOrdinancePhaseStarted()
        {
            this.currentPhase = TurnPhases.Ordinance;

            if (this.OrdinancePhaseStarted == null) return;

            this.OrdinancePhaseStarted(this, EventArgs.Empty);
        }

        /// <summary>
        /// Event raised when the current <see cref="GameTurn"/> enters the ordinance phase.
        /// </summary>
        /// <remarks>
        /// This is when players may move any <see cref="Ordinance">ordianance</see> currently on the tabletop
        /// (including ordianance just launched during the <see cref="ShootingPhaseStarted">shooting phase</see>.
        /// </remarks>
        public event EventHandler OrdinancePhaseStarted;

        /// <summary>
        /// Raises the <see cref="EndPhaseStarted"/> event.
        /// </summary>
        protected virtual void OnEndPhaseStarted()
        {
            this.currentPhase = TurnPhases.End;

            if (this.EndPhaseStarted == null) return;

            this.EndPhaseStarted(this, EventArgs.Empty);
        }

        /// <summary>
        /// Event raised when the current <see cref="GameTurn"/> enters the end phase.
        /// </summary>
        /// <remarks>
        /// This is when players may attempt to repair critical damage which has been inflicted on their <see cref="Vessel">vessels</see>.
        /// </remarks>
        public event EventHandler EndPhaseStarted;

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raises the <see cref="PropertyChanged"/> event.
        /// </summary>
        /// <param name="propertyName">The name of the property that changed.</param>
        protected virtual void OnPropertyChanged(String propertyName)
        {
            if (this.PropertyChanged == null) return;

            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Raised when a property value has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
